package io.github.novaframe.common.util.http;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.ChallengeState;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.SocketConfig;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 
 * @author Locki
 * @date Apr 11, 2017 4:31:57 PM
 * @version 1.0
 *
 */
public class HttpClientUtil {
	
	private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

	private static PoolingHttpClientConnectionManager cm;

    private static void init() {
        if (cm == null) {
            cm = new PoolingHttpClientConnectionManager();
            cm.setMaxTotal(500); // 整个连接池最大连接数
            cm.setDefaultMaxPerRoute(100); // 每路由最大连接数，默认值是2
            //cm.setMaxPerRoute(null,2); // 单独为某个站点设置最大连接个数
        }
    }

    private static CloseableHttpClient getHttpClient(SocketConfig socketConfig) {
        init();
        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setUserAgent("");
        httpClientBuilder.setConnectionManager(cm);
        if (socketConfig != null) {
            httpClientBuilder.setDefaultSocketConfig(socketConfig);
        }
        return httpClientBuilder.build();
    }
	
	/**
	 * HTTP POST 
	 * Content-Type: application/x-www-form-urlencoded
	 * 
	 * @param url
	 * @param
	 * @return
	 * @throws IOException 
	 */
	public static HttpResp post(String url, Map<String, String> params) {
		RequestBuilder requestBuilder = RequestBuilder.post().setUri(url);
		for (Entry<String, String> entry : params.entrySet()) {
			NameValuePair nvp = new BasicNameValuePair(entry.getKey(), entry.getValue());
			requestBuilder.addParameter(nvp);
		}
		
		CloseableHttpResponse httpResponse = null;
		try {
			httpResponse = getHttpClient(null).execute(requestBuilder.build());
			int statusCode = httpResponse.getStatusLine().getStatusCode();
			
			if (statusCode == HttpStatus.SC_OK) {
				String content = EntityUtils.toString(httpResponse.getEntity());
				return new HttpResp(content);
			} else {
				// status error
				logger.warn("get url {} error, status code {} ", url, statusCode);
			}
			
		} catch (IOException e) {
			logger.warn("get url {} error", url, e);
		} finally {
			try {
			    if (httpResponse != null)
				    httpResponse.close();
			} catch (IOException e) {}
		}
		
		return new HttpResp();
	}
	
	/**
	 * HTTP GET
	 * 
	 * @param url
	 * @return
	 */
	public static String get(String url) {
		RequestBuilder requestBuilder = RequestBuilder.get().setUri(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(30000)
                .setConnectionRequestTimeout(10000)
                .setSocketTimeout(30000)
                .build();
        requestBuilder.setConfig(requestConfig);
		
		CloseableHttpResponse httpResponse = null;
		try {
			httpResponse = getHttpClient(null).execute(requestBuilder.build());
			int statusCode = httpResponse.getStatusLine().getStatusCode();
			
			if (statusCode == HttpStatus.SC_OK) {
				return EntityUtils.toString(httpResponse.getEntity());
			} else {
				// status error
				logger.warn("get url {} error, status code {} ", url, statusCode);
			}
			
		} catch (IOException e) {
			logger.error("get url {} error", url, e);
		} finally {
			try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
			} catch (IOException e) {}
		}
		
		return null;
	}
	
    /**
     * 简单的使用非匿名代理GET
     * @param url
     * @return
     * @throws IOException
     * @throws Exception
     */
    public static String proxyGet(String url, String proxyHost, Integer proxyPort, String proxyUser, String proxyPwd) {

        String result = "";

        //CredentialsProvider proxyCredsProvider = new BasicCredentialsProvider();
        //proxyCredsProvider.setCredentials(
        //        new AuthScope(proxyHost, proxyPort),
        //        new UsernamePasswordCredentials(proxyUser, proxyPwd));
        //httpClientBuilder.setDefaultCredentialsProvider(proxyCredsProvider);

        // 生成Client
        SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(5000).setSoKeepAlive(true).setTcpNoDelay(true).build();
        CloseableHttpClient httpClient = getHttpClient(socketConfig);

        // 生成request
        RequestBuilder requestBuilder = RequestBuilder.get();
        requestBuilder.setUri(url);
        HttpHost httpHost = new HttpHost(proxyHost, proxyPort);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000)
                .setSocketTimeout(5000)
                .setProxy(httpHost).build();

        requestBuilder.setConfig(requestConfig);
        HttpUriRequest httpUriRequest = requestBuilder.build();

        // 生成httpContext
        HttpClientContext httpContext = new HttpClientContext();
        if (StringUtils.isNotBlank(proxyUser)) {
            AuthState authState = new AuthState();
            authState.update(new BasicScheme(ChallengeState.PROXY), new UsernamePasswordCredentials(proxyUser, proxyPwd));
            httpContext.setAttribute(HttpClientContext.PROXY_AUTH_STATE, authState);
        }

        // 执行
        CloseableHttpResponse httpResponse = null;
        try {
            httpResponse = httpClient.execute(httpUriRequest, httpContext);
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) {
                if (HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode()) {
                    result = EntityUtils.toString(entity, "UTF-8");
                }
                EntityUtils.consume(entity);
            }
        } catch (IOException e) {
            logger.warn("ProxyGet error: {}", e.getMessage());
        } finally {
            try {
                if (httpResponse != null)
                    httpResponse.close();
            } catch (IOException e) {}
        }
        return result;
    }
}
